package com.audaque.springboot.foshanupload.minio.component;

import com.audaque.springboot.foshanupload.core.constants.ComConst;
import com.audaque.springboot.foshanupload.minio.model.dto.MinioFileInfoDto;
import com.audaque.springboot.foshanupload.minio.properties.MinIoProperties;
import io.minio.*;
import io.minio.http.Method;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zgb
 * @desc ...
 * @date 2022-03-27 22:33:28
 */
@Component
public class MinioProvider {
    @Autowired(required = false)
    private MinioClient minioClient;
    @Autowired
    private MinIoProperties minIoProperties;


    /**
     * 文件上传
     */
    public MinioFileInfoDto upload(MultipartFile file, String bucketName) throws Exception{
        boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (!isExist) {
            //创建存储桶并设置只读权限
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
        String filename = file.getOriginalFilename();
        LocalDateTime now = LocalDateTime.now();
        int year = now.getYear();
        int month = now.getMonth().getValue();
        int dayOfMonth = now.getDayOfMonth();
        // 设置存储对象名称
        String objectName =year + "/" +month + "/" + dayOfMonth + "/" +  filename;
        PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName)
                .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
        //文件名称相同会覆盖
        ObjectWriteResponse objectWriteResponse = minioClient.putObject(objectArgs);
        MinioFileInfoDto minioFileInfoDto = new MinioFileInfoDto();
        minioFileInfoDto.setFileUrl(minIoProperties.getEndpoint() + "/" + bucketName + "/" + objectName);
        minioFileInfoDto.setEndpoint(minIoProperties.getEndpoint() );
        minioFileInfoDto.setBucketName(bucketName);
        minioFileInfoDto.setObjectName(objectName);
        return minioFileInfoDto;
    }

    /**
     * 签名
     */
    public String getPresignedObjectUrl(String methodName,String bucketName,String fileName) throws Exception {
        LocalDateTime now = LocalDateTime.now();
        int year = now.getYear();
        int month = now.getMonth().getValue();
        int dayOfMonth = now.getDayOfMonth();
        // 设置存储对象名称
        String objectName =year + "/" +month + "/" + dayOfMonth + "/" +  fileName;
        int expiry= ComConst.SIGN_EXPIRY;
        Map<String, String> reqParams = new HashMap<String, String>();
        reqParams.put("response-content-type", "application/json");
        String url = minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.valueOf(methodName)) //这里必须是PUT，如果是GET的话就是文件访问地址了。如果是POST上传会报错.
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(expiry)
                        .extraQueryParams(reqParams)
                        .build());
        return url;
    }


    /**
     * 文件下载
     */
    public void download( String fileUrl, HttpServletResponse res) throws Exception {
        MinioFileInfoDto minioFileInfoDto = this.splitFileUrl(fileUrl);
        String bucketName = minioFileInfoDto.getBucketName();
        String objectName = minioFileInfoDto.getObjectName();
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName)
                .object(objectName).build();
        GetObjectResponse response = minioClient.getObject(objectArgs);
        try  {
            byte[] buf = new byte[1024];
            int len;
            try (FastByteArrayOutputStream os = new FastByteArrayOutputStream()) {
                while ((len = response.read(buf)) != -1) {
                    os.write(buf, 0, len);
                }
                os.flush();
                byte[] bytes = os.toByteArray();
                res.setCharacterEncoding("utf-8");
                //设置强制下载不打开
                res.setContentType("application/force-download");
                res.addHeader("Content-Disposition", "attachment;objectName=" + objectName);
                try (ServletOutputStream stream = res.getOutputStream()) {
                    stream.write(bytes);
                    stream.flush();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件详情
     */
    public MinioFileInfoDto detail( String fileUrl) throws Exception {
        MinioFileInfoDto minioFileInfoDto = this.splitFileUrl(fileUrl);
        String bucketName = minioFileInfoDto.getBucketName();
        String objectName = minioFileInfoDto.getObjectName();
        GetObjectArgs objectArgs = GetObjectArgs.builder().bucket(bucketName)
                .object(objectName).build();
        GetObjectResponse response = minioClient.getObject(objectArgs);
        minioFileInfoDto.setContentBytes(IOUtils.toByteArray(response));
        return minioFileInfoDto;
    }






    /**
     * 批量删除文件对象
     */
    public void removeObjects(List<String> fileUrlList) throws Exception{
        for (String fileUrl : fileUrlList) {
            MinioFileInfoDto minioFileInfoDto = this.splitFileUrl(fileUrl);
            String bucketName = minioFileInfoDto.getBucketName();
            String objectName = minioFileInfoDto.getObjectName();
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build();
            minioClient.removeObject(removeObjectArgs);
        }
    }


    private MinioFileInfoDto splitFileUrl(String fileUrl) throws Exception {
        //"http://localhost:9000/demo/2022/MARCH/28/中山三件套下周任务.doc",
        String[] split1 = fileUrl.split("://");
        if(split1.length==0){
            throw new Exception("fileUrl不符合规范");
        }
        String[] split2 = split1[1].split(":");
        if(split2.length==0){
            throw new Exception("fileUrl不符合规范");
        }
        String[] split3 = split2[1].split("/");
        String bucketName=split3[1];
        String[] split4 = fileUrl.split("/"+bucketName+"/");
        String objectName=split4[1];

        MinioFileInfoDto minioFileInfoDto = new MinioFileInfoDto();
        minioFileInfoDto.setFileUrl(minIoProperties.getEndpoint() + "/" + bucketName + "/" + objectName);
        minioFileInfoDto.setEndpoint(minIoProperties.getEndpoint() );
        minioFileInfoDto.setBucketName(bucketName);
        minioFileInfoDto.setObjectName(objectName);
        return minioFileInfoDto;
    }
}
